Skip to content

SECENG-13957: feat: add ML-DSA-44/65/87 post-quantum key support - #1445

Draft
ang-cloudflare wants to merge 6 commits into
cloudflare:masterfrom
ang-cloudflare:ang/SECENG-13957
Draft

ang-cloudflare wants to merge 6 commits into
cloudflare:masterfrom
ang-cloudflare:ang/SECENG-13957

Conversation

@ang-cloudflare

@ang-cloudflare ang-cloudflare commented Aug 26, 2026

Copy link
Copy Markdown

Summary

Add ML-DSA (FIPS 204) key generation and signature algorithm support using Go 1.27 crypto/mldsa. This enables the explicit mldsa44, mldsa65, and mldsa87 KeyRequest algorithm values for post-quantum certificate authority generation.

ML-DSA-44 is the downstream default when an ML-DSA variant is omitted. cfssl continues to accept only explicit parameter-set names; the omitted-selection default belongs in the calling service.

Changes

Core ML-DSA support

  • Generate ML-DSA-44/65/87 keys and select the matching X.509 signature algorithm.
  • Marshal private keys as seed-only PKCS#8 and parse them through the existing DER helpers.
  • Support ML-DSA certificates in bundling, CA renewal, key metadata, and display helpers.
  • Preserve errors for unsupported algorithms without falling back to RSA or ECDSA.

Verification

  • Cover key generation, CSR creation, PKCS#8 round trips, signature selection, self-signed CA creation, renewal, and bundling for all three parameter sets.
  • Round-trip the RFC 9881 ML-DSA-44 example private key.
  • Generate, parse, and verify ML-DSA-issued CRLs for all three parameter sets.
  • Run focused ML-DSA tests with GOFIPS140=latest and GODEBUG=fips140=on.

Go 1.27 migration

  • Raise the module minimum from Go 1.20 to Go 1.27. crypto/mldsa is unavailable before Go 1.27 and cannot be build-tagged.
  • Update CI and golangci-lint, remove the deleted x509sha1 GODEBUG override, and fix Go 1.27 compatibility and vet failures.

Dependency

Depends on #1434. Go 1.24 removed the x509sha1 compatibility override, and the existing SHA-1 test fixtures must be regenerated before the full suite can pass on Go 1.27. This PR does not disable those tests or duplicate the 76-file fixture rewrite.

Context

  • Jira: SECENG-13957
  • Current spec: PQC ML-DSA managed-CA generation in COMS
  • Production qualification uses the Cloudflare Go 1.27.1-1 or newer package with GOFIPS140=latest; this public workflow verifies compatibility with the corresponding upstream FIPS mode.
  • Downstream scope: COMS selection/defaulting, KDL/GKA wrapping, and the wrapped-key /gencrl endpoint remain integration responsibilities outside this repository.
  • Not in scope: hybrid/composite mldsa44p256 certificates or CSR-signed PQ leaf certificates.

Add ML-DSA (FIPS 204) key generation and signature algorithm support
using Go 1.27's crypto/mldsa stdlib package.

Changes:
- KeyRequest.Generate() supports mldsa44, mldsa65, mldsa87 algo values
- KeyRequest.SigAlgo() maps ML-DSA variants to x509.MLDSA44/65/87
- DefaultSigAlgo() and SignerAlgo() handle *mldsa.PublicKey
- ParsePrivateKeyDER() recognizes *mldsa.PrivateKey via PKCS#8
- ParseRequest() marshals ML-DSA keys as PKCS#8 ("PRIVATE KEY" PEM)
- initca.New() works end-to-end for all three ML-DSA parameter sets

Breaking change: raises go.mod minimum to Go 1.27. crypto/mldsa does
not exist in earlier versions and cannot be build-tagged.

Go 1.27 compatibility fixes:
- transport/roots/system: fix initSystemRoots() signature for Go 1.27
- helpers_test: fix 256-bit RSA key generation (rejected in Go 1.27)
- signer/local: use OID-based CT poison lookup in TestSignFromPrecert
- signer/local: update TestLint expectations for Go 1.27 zlint results
- CI: update to Go 1.27, upgrade golangci-lint-action to v9
@ang-cloudflare
ang-cloudflare marked this pull request as draft August 26, 2026 23:08

@ang-cloudflare ang-cloudflare left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Scout Review

Comment — 3 findings worth addressing, none blocking.

The core ML-DSA support (key generation, sig algo mapping, PKCS#8 serialization, DER parsing) is correctly implemented. These are cross-boundary gaps in subsystems the PR doesn't touch yet — fixing them here keeps the feature internally consistent.

See inline comments for details.

Comment thread helpers/helpers.go
Comment thread initca/initca_test.go
Comment thread helpers/helpers.go
… display functions

- bundler: accept ML-DSA certs in Bundle() key validation (key-present
  and keyless paths), add MLDSA key type and PKCS#8 serialization to
  MarshalJSON
- initca: add ML-DSA case to RenewFromSigner() key matching
- helpers: KeyLength() returns public key byte size (1312/1952/2592)
  per PQC func spec; SignatureString() and HashAlgoString() return
  MLDSA44/65/87 instead of "Unknown"
Comment thread bundler/bundle.go Outdated
Comment thread bundler/bundle.go
Comment thread helpers/helpers.go
- bundler: use ML-DSA-44/65/87 names instead of byte count for keyType
- helpers: use Parameters().PublicKeySize() instead of hardcoded values
  in KeyLength()
- derhelpers: add RFC 9881 ML-DSA-44 example private key round-trip test
Comment thread cmd/multirootca/ca.go
Comment thread csr/csr.go
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants